import cv2
import numpy as np
import os
import csv


def canny(image_folder, output_csv, output_image_folder):
    features_and_labels = []
    if not os.path.exists(output_image_folder):
        os.makedirs(output_image_folder)

    if not os.path.isdir(image_folder):
        print("Error: Image folder not found.")
    else:
        results = []
        for image_filename in os.listdir(image_folder):
            if image_filename.endswith(".jpg"):
                image_path = os.path.join(image_folder, image_filename)
                image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

                if image is not None:
                    # 高斯模糊到原始图像，以减少噪声
                    blurred_image = cv2.GaussianBlur(image, (5, 5), 0)

                    # 使用Canny边缘检测器在模糊图像上检测边缘，作为真值边缘
                    low_threshold = 50
                    high_threshold = 150
                    edges_canny = cv2.Canny(blurred_image, low_threshold, high_threshold)

                    edges_canny_vector = edges_canny.flatten()
                    norm_factor = np.linalg.norm(edges_canny_vector)
                    if norm_factor == 0:
                        edges_canny_norm = np.zeros_like(edges_canny_vector)
                    else:
                        edges_canny_norm = edges_canny_vector / norm_factor
                        features_and_labels.append([edges_canny_norm, image_filename])

                    # 计算能量和标准差
                    energy = np.sum(edges_canny ** 2)  # 能量：较高的能量可能意味着图像具有更多的细节和边缘，可以被解释为图像具有更高的“信息量”，若能量过高，也可能是由于噪声或图像过度锐化导致的
                    std_dev = np.std(edges_canny)  # 标准差越高的图像表明其像素值变化较大，可能意味着图像具有更多的对比度和细节，但如果标准差过高，也可能意味着图像存在较大的噪声，在图像清晰度评估时，需要选取适中的标准差

                    # 计算边缘检测的准确率
                    true_positives = np.sum((edges_canny == 255) & (image > 0))
                    false_positives = np.sum((edges_canny == 255) & (image == 0))
                    false_negatives = np.sum((edges_canny == 0) & (image > 0))

                    precision = true_positives / (true_positives + false_positives)
                    recall = true_positives /(true_positives + false_negatives)
                    f1_score = 2 * (precision * recall) / (precision + recall)

                    results.append([
                        image_filename,
                        precision,
                        recall,
                        f1_score,
                        energy,
                        std_dev
                    ])
                    comparison_image = np.hstack((image, edges_canny))
                    cv2.imshow('Comparison Image', comparison_image)

                    output_image_path = os.path.join(output_image_folder, image_filename)
                    cv2.imwrite(output_image_path, comparison_image)
        print(features_and_labels)


        with open(output_csv, mode='w', newline='') as file:
            writer = csv.writer(file)
            writer.writerow(['Image Filename','Precision','Recall','F1 Score','Energy','Standard Deviation'])
            writer.writerows(results)

        print(f"Results have been written to {output_csv}")

        cv2.waitKey(0)
        cv2.destroyAllWindows()

    return features_and_labels

